#pragma once

/*
edit: sunkun
usage:

see  demo
int main() {

		DimensionCamera *cam = new DimensionCamera();
		cam->InfoFramegrabber("SDK", "info", &cam->_Information, &cam->_ValueList);
		for (auto& dc : cam->getCameraInfoByVendorNameCameraMap()) {
			std::cout << "camera vendor:" << dc.first << std::endl;
			for (auto& hl : dc.second->HandleList) {
				dc.second->OpenFramegrabberSimgple(&hl, "line0");
				DimensionCamera::DimInfo Image;
				dc.second->GrabImage(hl.Handle,&Image);
				//printf_s("device add %p\n", hl.Handle);
				printf_s("image address %p W:%d H:%d\n", Image.data, Image.width, Image.height);
			}
		}

		//if camera link break for some reason, try to reinitialized it
		delete cam;
		cam = nullptr;
		cam = new DimensionCamera();

		cam->InfoFramegrabber("SDK", "info", &cam->_Information, &cam->_ValueList);
		for (auto& dc : cam->getCameraInfoByVendorNameCameraMap()) {
			std::cout << "camera vendor:" << dc.first << std::endl;
			for (auto& hl : dc.second->HandleList) {
				dc.second->OpenFramegrabberSimgple(&hl, "line0");
				DimensionCamera::DimInfo Image;
				clock_t clk = clock();
				dc.second->GrabImage(hl.Handle, &Image);
				clock_t cost = clock() - clk;
				printf_s("snap cost time %zd, image address %p W:%d H:%d\n",cost, Image.data, Image.width, Image.height);
			}
		}

		//free source
		delete cam;
	return 0;
}

*/
//snap 
#include <vector>
#include <iostream>
#include <unordered_map>

#ifdef CAM_LIBRARY
#define CAM_API __declspec(dllexport)
#else
#define CAM_API __declspec(dllimport)
#endif

#define MAX_DEVICE_NUM 16


enum DIM_ERROR {
	DIM_ERROR_SUCCESS = 0,
	DIM_ERROR_VIRTUAL_FUNCTION = 1
};

#ifdef __cplusplus
extern "C" {
#endif

	template class CAM_API std::allocator<std::string>;
	template class CAM_API std::vector<std::string, std::allocator<std::string> >;
	class CAM_API DimensionCamera
	{
	public:
		DimensionCamera() {}
		virtual ~DimensionCamera();

		class DimInfo {
		public:
			//image data information
			unsigned char* data = nullptr;
			unsigned char* rawData = nullptr;
			long long width = 0;
			long long height = 0;
			long long channel = 3;
			//appendinfo
			std::string UsrName = "";  //dev name, will get the user name
			std::string Vendor = "";   //camera vendor name
			std::string ErrorInfo = "";
			int DevIndex = 0;          //get the index stored in DevIndex
			void* Handle = nullptr;    //camera handle
			long long bayerLayout = 0;
			long long payLoadSize = 0;
			bool isColor() { return ColorFilter; }
			void setColor(bool isTrue) { ColorFilter = isTrue; }
			~DimInfo() {
				if (nullptr != data) {
					delete data;
					data = nullptr;
				}
				if (nullptr != rawData) {
					delete rawData;
					rawData = nullptr;
				}
			}
		protected:
			bool ColorFilter = false;
		};

		using AcqInfoList = std::vector<DimInfo>;
		using AcqHandle = void*;
		using DStringList = std::vector<std::string>;

		/*
		* type Value:
			GigeVision2, SDK,

			info Value:
			info_boards

		*/
		virtual void  InfoFramegrabber(std::string type = "GigEVision2", std::string info = "info_boards", DStringList* Info = nullptr, DStringList* ValueList = nullptr);
		virtual int OpenFramegrabberSimgple(DimInfo*, std::string SnapMethod = "line0");
		virtual bool GrabImage(AcqHandle, DimInfo* ImageData);
		std::unordered_map<std::string, DimensionCamera*>& getCameraInfoByVendorNameCameraMap();
		//		virtual int DeviceNumber(DimInfo* dimInfo);
		//		virtual DimInfo * getDeviceDimInfo(int HandListIndex = 0);
		virtual const char* type();

		DStringList _Information, _ValueList;
		AcqInfoList HandleList;
	private:
		std::unordered_map<std::string, DimensionCamera*> CameraMap;
	};

#ifdef __cplusplus
}
#endif
